package com.cipe.cmrs.controllers;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.cipe.cmrs.bean.ProjectReportBean;
import com.cipe.cmrs.model.Cipeproject;
import com.cipe.cmrs.model.Projectreport;
import com.cipe.cmrs.service.CipeprojectService;
import com.cipe.cmrs.service.ProjectReportService;
import com.cipe.cmrs.util.Constants;

/**
 * 
 * @author krishna (kanhu.aum@gmail.com)
 *
 */
/*
 * TODO [Allan]: Refactor the entire module. We could use javascript to cater CRUD of
 * rows. I wonder why submission is needed just to achieve CRUD operation of
 * rows
 */
@Controller
public class ProjectReportController extends BaseController{
	private static final long serialVersionUID = -2482539586632027078L;
	
	// static variables related to progress reports
	public static final String REDIRECT_TO_REPORT_LIST_PAGE = "redirect:showAddReportingrequirements.do?cipeprojectId=";
	private static final String SHOW_REPORT_LIST_URL = "/secure/saveProjectReportLines.do";
	
	@Autowired
	ProjectReportService projectReportService;
	@Autowired
	private CipeprojectService cipeprojectService;
	
	@RequestMapping("/secure/findResultProjectReportWithProcedure.do")
	public String findResultProjectReportWithProcedure(@ModelAttribute("report") Projectreport projectreport, Model model) {
	model.addAttribute("reportList", projectReportService.findallProjectReport(projectreport.getPrc()));
	model.addAttribute("message", projectreport.getMessage());
	return "findProjectreport";
	}

	/**
	 * Initial show of list.
	 */
    @RequestMapping(value = "/secure/showAddReportingrequirements.do", method = RequestMethod.GET)
	public String showAddReportingrequirements(@RequestParam Integer cipeprojectId, @RequestParam(value="narEdit", required=false) Boolean narrativeSectionEditable,
				@RequestParam(value="finEdit", required=false) Boolean financialSectionEditable, Model model) {
    	constructListOfReports(cipeprojectId, narrativeSectionEditable, financialSectionEditable, model);
    	
    	Cipeproject cipeproject = cipeprojectService.findById(cipeprojectId);
		model.addAttribute("cipeproject", cipeproject);
		
		return "editReportingrequirements";
	}	
	
	/**
	 * Handles the edit operation for narrative reports.
	 */
    @RequestMapping(value = SHOW_REPORT_LIST_URL, params="edtRowNar", method = RequestMethod.POST)
	public String editNarrativeReportingrequirements(@ModelAttribute("projectReportBean") ProjectReportBean projectReportBean, Model model) {
    	
    	// clears first the list of records
    	projectReportBean.getNarrativeReports().clear();
    	
    	// load the existing lines for the current type     	
    	constructListOfReportsForType(projectReportBean, true, false, model);
		
    	// set a flag
    	projectReportBean.setNarrativeSectionEditable(true);
    	
    	Cipeproject cipeproject = cipeprojectService.findById(projectReportBean.getCipeprojectId());
		model.addAttribute("cipeproject", cipeproject);
		
		return "editReportingrequirements";
	}
    
    /**
     * Handles the edit operation for financial reports.
     */
    @RequestMapping(value = SHOW_REPORT_LIST_URL, params="edtRowFin", method = RequestMethod.POST)
	public String editFinancialReportingrequirements(@ModelAttribute("projectReportBean") ProjectReportBean projectReportBean, Model model) {
    	
    	// clears first the list of records
    	projectReportBean.getFinancialReports().clear();
		
    	// load the existing lines for the current type 
    	constructListOfReportsForType(projectReportBean, false, true, model);
    	
    	// set a flag    	
    	projectReportBean.setFinancialSectionEditable(true);
    	
    	Cipeproject cipeproject = cipeprojectService.findById(projectReportBean.getCipeprojectId());
		model.addAttribute("cipeproject", cipeproject);
		
		return "editReportingrequirements";
	}
    
    @RequestMapping(value = SHOW_REPORT_LIST_URL, params = "addRowNar", method = RequestMethod.POST)
    public String addNarrativeReportingrequirements(@ModelAttribute("projectReportBean") ProjectReportBean projectReportBean,
        Model model) {
        projectReportBean.setNarrativeReportSize(projectReportBean.getNarrativeReportSize() + 1);
        projectReportBean.getNarrativeReports().add(new Projectreport(Constants.NARRATIVE_TYPE));

        Cipeproject cipeproject = cipeprojectService.findById(projectReportBean.getCipeprojectId());
        model.addAttribute("cipeproject", cipeproject);
        model.addAttribute("projectReportBean", projectReportBean);
        return "editReportingrequirements";
    }

    @RequestMapping(value = SHOW_REPORT_LIST_URL, params = "addRowFin", method = RequestMethod.POST)
    public String addFinancialReportingrequirements(@ModelAttribute("projectReportBean") ProjectReportBean projectReportBean,
        Model model) {
        projectReportBean.setFinancialReportSize(projectReportBean.getFinancialReportSize() + 1);
        projectReportBean.getFinancialReports().add(new Projectreport(Constants.FINANCIAL_TYPE));

        Cipeproject cipeproject = cipeprojectService.findById(projectReportBean.getCipeprojectId());
        model.addAttribute("cipeproject", cipeproject);
        model.addAttribute("projectReportBean", projectReportBean);
        return "editReportingrequirements";
    }
    
    /**
     * Load the reports for a specific type and constructs the corresponding list.
     */
    private void constructListOfReportsForType(ProjectReportBean projectReportBean, Boolean narrativeSectionEditable, Boolean financialSectionEditable, Model model) {
    	
    	if(narrativeSectionEditable || !projectReportBean.isNarrativeSectionEditable()) projectReportBean.getNarrativeReports().clear();
    	if(financialSectionEditable || !projectReportBean.isFinancialSectionEditable()) projectReportBean.getFinancialReports().clear();
    	
    	// loads the reports
    	List<Projectreport> projectReports = projectReportService.findProjectReportsByProjectId(projectReportBean.getCipeprojectId());
    	if(projectReports != null && !projectReports.isEmpty()) {
    	    projectReportBean.setHasExistingReports(true);
    		for(Projectreport report : projectReports) {
    			if((narrativeSectionEditable || !projectReportBean.isNarrativeSectionEditable()) && Constants.NARRATIVE_TYPE.equals(report.getType())) {
					projectReportBean.addNarrativeReport(report);
				} 
    			if((financialSectionEditable || !projectReportBean.isFinancialSectionEditable()) && Constants.FINANCIAL_TYPE.equals(report.getType())) {
    				projectReportBean.addFinancialReport(report);
    			}
    		}
    	}
    			
    	// complete the reporting lines up to the MAX_REPORTINGS_DEFAULT_NUMBER number
    	if(narrativeSectionEditable) { // for narrative type
	    	if(projectReportBean.getNarrativeReports().size() < projectReportBean.getNarrativeReportSize()) {
                for (int i = projectReportBean.getNarrativeReports().size() + 1; i <= projectReportBean.getNarrativeReportSize(); i++) {
					projectReportBean.addNarrativeReport(new Projectreport(Constants.NARRATIVE_TYPE));
				}
			} else {
				projectReportBean.addNarrativeReport(new Projectreport(Constants.NARRATIVE_TYPE));
			}
    	}
    	
    	if(financialSectionEditable) {  // for financial type
	    	if(projectReportBean.getFinancialReports().size() < projectReportBean.getFinancialReportSize()) {
                for (int i = projectReportBean.getFinancialReports().size() + 1; i <= projectReportBean.getFinancialReportSize(); i++) {
	    			projectReportBean.addFinancialReport(new Projectreport(Constants.FINANCIAL_TYPE));
	    		}
	    	} else {
	    		projectReportBean.addFinancialReport(new Projectreport(Constants.FINANCIAL_TYPE));
	    	}
    	}
    	
    }
 
    /**
     * Loads all the records for both types.
     */
	private void constructListOfReports(Integer cipeprojectId, Boolean narrativeSectionEditable, Boolean financialSectionEditable, Model model) {
		ProjectReportBean projectReportBean = new ProjectReportBean(cipeprojectId);
		
		// load the existing lines for the both types     	
    	constructListOfReportsForType(projectReportBean, true, true, model);
	
		projectReportBean.setNarrativeSectionEditable((narrativeSectionEditable != null && narrativeSectionEditable == true) ? true : false);
		projectReportBean.setFinancialSectionEditable((financialSectionEditable != null && financialSectionEditable == true) ? true : false);
		
		model.addAttribute("projectReportBean", projectReportBean);		
		
	}
	
	/**
	 * Handles the save operation for both types.
	 */
	@RequestMapping(value=SHOW_REPORT_LIST_URL, method=RequestMethod.POST)
	public String saveNarrativeAndFinancialReportLines(@ModelAttribute("projectReportBean") ProjectReportBean projectReportBean, 
			BindingResult result, Model model, HttpServletRequest request) {

		if (!result.hasErrors()) {
            boolean reportsAreSaved = !projectReportBean.isHasExistingReports();
			projectReportService.persistProjectReportData(projectReportBean);
			shiftFilledRows(projectReportBean);
			saveMessage(request, getText("editReportingrequirements.save.success"));
			model.addAttribute("reportsAreSaved", reportsAreSaved);
		}
		
		model.addAttribute("projectReportBean", projectReportBean);
		
    	Cipeproject cipeproject = cipeprojectService.findById(projectReportBean.getCipeprojectId());
		model.addAttribute("cipeproject", cipeproject);
		
		return "editReportingrequirements";
	}
	
    private void shiftFilledRows(ProjectReportBean projectReportBean) {
        if (projectReportBean.isNarrativeSectionEditable() == true) {
            List<Projectreport> filledReports = new ArrayList<Projectreport>();
            List<Projectreport> emptyReports = new ArrayList<Projectreport>();
            List<Projectreport> reports = projectReportBean.getNarrativeReports();
            if (reports != null) {
                for (Projectreport report : reports) {
                    if (!report.isEmpty()) {
                        filledReports.add(report);
                    } else {
                        emptyReports.add(report);
                    }
                }
            }
            reports.clear();
            reports.addAll(filledReports);
            reports.addAll(emptyReports);
        }

        if (projectReportBean.isFinancialSectionEditable() == true) {
            List<Projectreport> filledReports = new ArrayList<Projectreport>();
            List<Projectreport> emptyReports = new ArrayList<Projectreport>();
            List<Projectreport> reports = projectReportBean.getFinancialReports();
            if (reports != null) {
                for (Projectreport report : reports) {
                    if (!report.isEmpty()) {
                        filledReports.add(report);
                    } else {
                        emptyReports.add(report);
                    }
                }
            }
            reports.clear();
            reports.addAll(filledReports);
            reports.addAll(emptyReports);
        }
    }
	
	/**
	 * Handles the delete operation for narrative type.
	 */
	@RequestMapping(value=SHOW_REPORT_LIST_URL, params="delRowNar", method=RequestMethod.POST)
	public String deleteNarrativeSelectedRows(@ModelAttribute("projectReportBean") ProjectReportBean projectReportBean, 
			@RequestParam Integer[] selNar, BindingResult result, Model model, HttpServletRequest request) {
		
		deleteSelectedRows(selNar);
		saveMessage(request, getText("editReportingrequirements.delete.success"));
	
		//constructListOfReports(projectReportBean.getCipeprojectId(), projectReportBean.isNarrativeSectionEditable(), 
			//	projectReportBean.isFinancialSectionEditable(), model);
		
		constructListOfReportsForType(projectReportBean, true, false, model);
		
    	Cipeproject cipeproject = cipeprojectService.findById(projectReportBean.getCipeprojectId());
		model.addAttribute("cipeproject", cipeproject);
		
		return "editReportingrequirements";
	}
	
	/**
	 * Handles the delete operation for financial type.
	 */
	@RequestMapping(value=SHOW_REPORT_LIST_URL, params="delRowFin", method=RequestMethod.POST)
	public String deleteFinancialSelectedRows(@ModelAttribute("projectReportBean") ProjectReportBean projectReportBean, 
			@RequestParam Integer[] selFin, BindingResult result, Model model, HttpServletRequest request) {
		
		deleteSelectedRows(selFin);
		saveMessage(request, getText("editReportingrequirements.delete.success"));
		
	//	constructListOfReports(projectReportBean.getCipeprojectId(), projectReportBean.isNarrativeSectionEditable(), 
	//			projectReportBean.isFinancialSectionEditable(), model);
		
		constructListOfReportsForType(projectReportBean, false, true, model);
		
    	Cipeproject cipeproject = cipeprojectService.findById(projectReportBean.getCipeprojectId());
		model.addAttribute("cipeproject", cipeproject);
		
		return "editReportingrequirements";
	}	
	
	/**
	 * Deletes a specific row by invoking the service.
	 */
	private void deleteSelectedRows(Integer[] reportIds) {
		if(reportIds != null) {
			for(Integer reportId: reportIds) {
				projectReportService.deleteReportLineById(reportId);
			}
		}
	}


}
